﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using ElementClasses;

namespace ExDayBook
{

    public partial class FormDayBook : Form
    {
        //public string txt { get { return textBox1.Text; } set { textBox1.Text = value; } }
        List<DayNote> nl = new List<DayNote>();

        public FormDayBook()
        {
            InitializeComponent();
        }

        void ChaildNote_Deleted(object sender, EventArgs e)
        {
            DayNote note = (DayNote)sender;
            nl.Remove(note);
            note.Dispose();
            SetVerticalPosElements();
        }

        void ChaildNote_ChangeHeight(object sender, EventArgs e)
        {
            SetVerticalPosElements();
        }

        void ChaildNote_AddNewElement(object sender, EventArgs e)
        {
            btnAdd_Click(null, null);
        }

        private void FormDayBook_Shown(object sender, EventArgs e)
        {
            pnlMain.Focus();
            btnAdd.Left = pnlMain.ClientRectangle.Width - 23;
            SetVerticalPosElements();
        }

        private void pnlMain_MouseDown(object sender, MouseEventArgs e)
        {
            pnlMain.Focus();
        }

        // устанавливаем ширину и позицию по высоте всех элементов
        public void SetVerticalPosElements()
        {
            int PosY = 5; // позиция следующего элемента.
            foreach (DayNote note in nl)
            {
                note.PosY = PosY;
                PosY += note.Height;
            }
            btnAdd.Top = PosY;
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            DayNote note = new DayNote(null, pnlMain, new EventHandler(ChaildNote_Deleted), new EventHandler(ChaildNote_ChangeHeight), new EventHandler(ChaildNote_AddNewElement));
            nl.Add(note);
            note.Focus();
            SetVerticalPosElements();
        }

        private void textBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            e.IsInputKey = true;
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            e.SuppressKeyPress = true;
        }

        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            //e.Handled = true;
        }

    }

    class DayNote : IDisposable
    {
        public List<DayNote> nl = new List<DayNote>();

        TextBox txb = new TextBox();
        Button btnOpen = new Button();
        Button btnAdd = new Button();
        Label lblHide = new Label();
        ContextMenu menu = new ContextMenu();
        Panel pnlParent;

        Panel pnlChaild = new Panel();

        public event EventHandler Deleted;
        public event EventHandler ChangeHeight;
        public event EventHandler AddNewElement;

        public DayNote Parent;

        const int chaildShiftX = 30;
        const int chaildSpaceOpenY = 8;
        const int chaildSpaceCloseY = 5;

        public int PosY
        {
            get
            {
                return txb.Top;
            }
            set
            {
                txb.Top = value;
                btnOpen.Top = value + 2;
                pnlChaild.Top = txb.Bottom - 5;
            }
        }

        public int Height
        {
            get
            {
                int ret = txb.Height;
                if (IsOpen)
                {
                    foreach (DayNote note in nl)
                    {
                        ret += note.Height;
                    }
                    ret += btnOpen.Height;
                    ret += chaildSpaceOpenY;
                }
                else if (nl.Count > 0) ret += chaildSpaceCloseY;
                return ret;
            }
        }

        /*public int Width
        {
            get
            {
                return txb.Width;
            }
            set
            {
                txb.Width = value;
                pnlChaild.Width = txb.Width - chaildShiftX;
                txbNew.Width = txb.Width - chaildShiftX;
                btnAdd.Left = txb.Right - 17;
                
                foreach (DayNote note in nl)
                {
                    note.Width = txb.Width - chaildShiftX;
                }
            }
        }*/

        public string Text { get { return txb.Text; } set { txb.Text = value; } }

        public bool IsOpen { get { return btnOpen.Text == "-"; } }

        public DayNote(DayNote Parent, Panel pnlParent, EventHandler Deleted, EventHandler ChangeHeight, EventHandler AddNewElement)
        {
            this.Parent = Parent;
            this.pnlParent = pnlParent;
            this.Deleted += Deleted;
            this.ChangeHeight = ChangeHeight;
            this.AddNewElement = AddNewElement;

            #region *** инициализация компонентов *************
            // --- txb ----------------------
            txb.MouseMove += new MouseEventHandler(txb_MouseMove);
            txb.KeyDown += new KeyEventHandler(txb_KeyDown);
            txb.TextChanged += new EventHandler(txb_TextChanged);
            txb.Left = 5;
            txb.Width = pnlParent.ClientRectangle.Width - 10;
            txb.ContextMenu = menu;
            txb.Multiline = true;
            // --- btnOpen ----------------------
            btnOpen.Text = "+";
            btnOpen.Size = new Size(16, 16);
            btnOpen.UseCompatibleTextRendering = true;
            btnOpen.Visible = false;
            btnOpen.MouseLeave += new EventHandler(btnOpen_MouseLeave);
            btnOpen.Click += new EventHandler(btnOpen_Click);
            btnOpen.Left = txb.Right - 17;
            // --- pnlChaild ----------------------
            pnlChaild.BorderStyle = BorderStyle.FixedSingle;
            pnlChaild.Visible = false;
            pnlChaild.Width = txb.Width - chaildShiftX;
            pnlChaild.MouseDown += new MouseEventHandler(delegate(object sender, MouseEventArgs e) { pnlChaild.Focus(); });
            pnlChaild.Controls.Add(btnAdd);
            pnlChaild.Left = 5 + chaildShiftX;
            // --- btnAdd ----------------------
            btnAdd.Location = new System.Drawing.Point(pnlChaild.ClientRectangle.Width - 23, 5);
            btnAdd.Size = new System.Drawing.Size(18, 18);
            btnAdd.UseVisualStyleBackColor = true;
            btnAdd.Click += new System.EventHandler(btnAdd_Click);
            // --- pnlParent ----------------------
            pnlParent.Controls.Add(lblHide);
            pnlParent.Controls.Add(txb);
            pnlParent.Controls.Add(pnlChaild);
            pnlParent.Controls.Add(btnOpen);
            // --- menu ----------------------
            menu.MenuItems.Add(new MenuItem("Удалить", mBtnDelete_Click));
            // --- lblHide ----------------------
            lblHide.Visible = false;
            lblHide.AutoSize = true;

            // вывод кнопки открытия наверх
            btnOpen.BringToFront();
            #endregion *** инициализация компонентов *************

            ResizePnlChaild();
            SetVerticalPosElements();
        }

        // устанавливаем ширину и позицию по высоте всех дочерних элементов
        void SetVerticalPosElements()
        {
            int PosY = 5; // позиция следующего элемента.
            foreach (DayNote note in nl)
            {
                note.PosY = PosY;
                PosY += note.Height;
            }
            btnAdd.Top = PosY;
        }

        // выставить высоту дочерней панели по количеству элементов
        bool ResizePnlChaild()
        {
            int oldH = pnlChaild.Height;
            int newH = chaildSpaceOpenY + btnAdd.Height;
            foreach (DayNote note in nl) newH += note.Height;
            if(oldH!=newH)
            {
                pnlChaild.Height = newH;
                return true;
            }

            return false;
        }

        // добавление дочернего элемента
        void btnAdd_Click(object sender, EventArgs e)
        {
            AddNewChaild();
        }

        void AddNewChaild()
        {
            DayNote note = new DayNote(this, pnlChaild, new EventHandler(ChaildNote_Deleted), new EventHandler(ChaildNote_ChangeHeight), new EventHandler(ChaildNote_AddNewElement));
            nl.Add(note);
            ResizePnlChaild();
            SetVerticalPosElements();
            note.txb.Focus();

            // поскольку добавился дочерний элемент, вызвать событие изменения высоты
            ChangeHeight(this, new EventArgs());
        }

        #region *** события дочерних элементов *************************

        // удаление дочернего элемента
        void ChaildNote_Deleted(object sender, EventArgs e)
        {
            DayNote note = (DayNote)sender;
            nl.Remove(note);
            note.Dispose();
            ResizePnlChaild();
            SetVerticalPosElements();

            // поскольку удален дочерний элемент, вызвать событие изменения высоты
            ChangeHeight(this, new EventArgs());
        }

        void ChaildNote_AddNewElement(object sender, EventArgs e)
        {
            AddNewChaild();
        }

        // событие: изменилась высота у одного из дочерних элементов
        void ChaildNote_ChangeHeight(object sender, EventArgs e)
        {
            // если дочерние элементы открыты, общая высота тоже изменилась. Вызвать событие изменения высоты
            if (IsOpen)
            {
                ResizePnlChaild();
                SetVerticalPosElements();
                ChangeHeight(this, new EventArgs());
            }
        }

        #endregion *** события дочерних элементов *************************

        // кнопка вызваа удаления этого элемента
        private void mBtnDelete_Click(object sender, EventArgs e)
        {
            if (txb.Text.Trim() != "") if (MessageBox.Show("Запись содержит текст. Действительно удалить?", "Удаление", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return;
            Deleted(this, new EventArgs());
        }

        // удажение элемента с панели
        public void Dispose()
        {
            pnlParent.Controls.Remove(txb);
            txb.Dispose();
            pnlParent.Controls.Remove(btnOpen);
            btnOpen.Dispose();
            menu.Dispose();
            foreach (DayNote note in nl) note.Dispose();
            nl.Clear();
            pnlChaild.Dispose();
            pnlParent.Controls.Remove(pnlChaild);
        }

        void txb_MouseMove(object sender, MouseEventArgs e)
        {
            btnOpen.Visible = nl.Count > 0 || IsOpen || e.X >= (txb.Width - 20);
        }

        void txb_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.Enter)
            {
                e.SuppressKeyPress = true;
                AddNewElement(this, null);
            }
            /*if (e.KeyCode == Keys.Back && txb.Text=="")
            {
                Deleted(this, new EventArgs());
            }*/
        }

        private void txb_TextChanged(object sender, EventArgs e)
        {
            if (txb.Multiline)
            {
                int oldH = txb.Height;
                lblHide.MaximumSize = new Size(txb.ClientSize.Width, int.MaxValue);
                lblHide.Text = txb.Text;
                if (txb.Text.Length > 0) if (txb.Text[txb.Text.Length - 1] == '\n') lblHide.Text += " ";
                txb.Height = lblHide.Height + 7;
                if (oldH != txb.Height)
                {
                    ChangeHeight(this, new EventArgs());
                }
            }
        }

        void btnOpen_MouseLeave(object sender, EventArgs e)
        {
            if (nl.Count == 0 && !IsOpen) btnOpen.Visible = false;
            txb.Focus();
            txb.Select(txb.Text.Length, 0);
        }

        void btnOpen_Click(object sender, EventArgs e)
        {
            if (!IsOpen)
            {
                btnOpen.Text = "-";
                pnlChaild.Visible = true;
            }
            else
            {
                btnOpen.Text = "+";
                pnlChaild.Visible = false;
            }
            // поскольку открывается или закрывается дочерняя панель, вызвать событие изменения высоты
            ChangeHeight(this, null);
        }

        public void Focus()
        {
            txb.Focus();
        }
    }

}
